package graphics.objects;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.ArrayList;

import network.byteConversions.ByteConverter;

import org.lwjgl.opengl.GL11;

import physics.Body;
import tools.Floatmath;
import tools.Help;
import tools.Log;
import tools.Point;
import graphics.effects.Compositor;
import graphics.system.Color;
import graphics.system.GLTools;
import graphics.system.VertexBufferObject;
import graphics.system.VertexBufferObject.Drawmode;
public class GPolygon extends GShape implements Serializable {
	private VertexBufferObject vbo;
	private ArrayList<Point> verts;
	public GPolygon(Point pos, Point verts[], float angle, Color color) {
		super(new Point(pos), angle, color);
		vbo = new VertexBufferObject(verts, Drawmode.POLYGON);
		this.verts = new ArrayList<Point>();
		for (Point pi : verts) {
			this.verts.add(pi);
		}
		node.boundingrad = 0;
		for (int i = 0; i < verts.length; i++) {
			node.boundingrad = Math.max(node.boundingrad, verts[i].length());
		}
		globalCoords = true;
	}
	public GPolygon() {
		super(new Point(0, 0), 0, Color.white);
		this.verts = new ArrayList<Point>();
	}
	@Override
	public void draw() {
		GL11.glPushMatrix();
		node.setUpGl();
		if (!hasTexture) {
			if (verts.size() > 2) {
				vbo.removeTexCoords();
				vbo.drawAt(Point.ZERO, 0, color);
			}
		}
		else {
			updateTexCoords();
			this.texture.bind();
			vbo.drawAt(Point.ZERO, 0, color);
		}
		GL11.glPopMatrix();
	}
	@Override
	public void drawSpec(Point lightPos, float lradius, Color lc, float zoom) {
		if (hasNormalmap) {
			// GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE); //Additive blend
			Color.white.set();
			Compositor.specular.enable();
			Compositor.specular.setParam2f("lpos", lightPos);
			Compositor.specular.setParamf("r", lc.r);
			Compositor.specular.setParamf("g", lc.g);
			Compositor.specular.setParamf("b", lc.b);
			Compositor.specular.setParamf("a", lc.a);
			Compositor.specular.setParamf("ca", 1);
			Compositor.specular.setParamf("sa", 0);
			Compositor.specular.setParamf("radius", lradius);
			Compositor.specular.setParami("bumpmap", 0);
			normalTexture.bind();
			GL11.glEnable(GL11.GL_TEXTURE_2D);
			GL11.glBegin(GL11.GL_POLYGON);
			for (int i = 0; i < verts.size(); i++) {
				Point cp = verts.get(i).rotate(node.apos);
				cp.x *= node.scale.x;
				cp.y *= node.scale.y;
				cp.sAdd(node.pos);
				GL11.glTexCoord2f(cp.x * this.globalCoordScale, cp.y * this.globalCoordScale);
				GL11.glVertex2f(cp.x, cp.y);
			}
			GL11.glEnd();
			GL11.glDisable(GL11.GL_TEXTURE_2D);
			Compositor.specular.disable();
		}
		else {
			// GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
			Compositor.enableShadowRender();
			this.draw();
			Compositor.disableShadowRender();
		}
	}
	private void updateTexCoords() {
		Point tc[] = new Point[verts.size()];
		for (int i = 0; i < verts.size(); i++) {
			Point cp = verts.get(i).rotate(node.apos);
			cp.x *= node.scale.x;
			cp.y *= node.scale.y;
			cp.sAdd(node.pos);
			tc[i] = new Point(cp.x * this.globalCoordScale, cp.y * this.globalCoordScale);
		}
		vbo.setTexCoords(tc);
	}
	@Override
	public void drawDebug() {
		this.draw();
		GL11.glPushMatrix();
		node.setUpGl();
		if (verts.size() > 1) {
			for (int i = 0; i < verts.size() - 1; i++) {
				GLTools.drawPoint(verts.get(i), Color.blue, 3);
				GLTools.drawLine(verts.get(i), verts.get(i + 1), Color.blue);
			}
			GLTools.drawPoint(verts.get(verts.size() - 1), Color.blue, 3);
			GLTools.drawLine(verts.get(0), verts.get(verts.size() - 1), Color.blue);
		}
		GL11.glPopMatrix();
	}
	public void addPoint(Point p) {
		for (Point pi : verts) {
			pi.sAdd(node.pos);
		}
		this.verts.add(p);
		Point c = new Point();
		for (Point pi : verts) {
			c.sAdd(pi);
		}
		c.sMul(1.0f / verts.size());
		this.node.pos = c;
		node.boundingrad = 0;
		for (Point pi : verts) {
			if (c.distance(pi) > node.boundingrad)
				node.boundingrad = c.distance(pi);
		}
		for (Point pi : verts) {
			pi.sSub(c);
		}
		if (verts.size() > 2) {
			if (vbo == null)
				vbo = new VertexBufferObject(getVerts(), Drawmode.POLYGON);
			else
				vbo.updateVerts(getVerts());
		}
	}
	public void clearPoints() {
		verts.clear();
		if (vbo != null) {
			vbo.delete();
			vbo = null;
		}
		node.pos = new Point();
		node.boundingrad = 0;
	}
	@Override
	public void drawShadow(Point lightPos, float radius) {
		if (!this.hasShadow)
			return;
		GL11.glPushMatrix();
		node.setUpGl();
		if (verts.size() > 2)
			vbo.drawAt(Point.ZERO, 0, Color.black);
		GL11.glPopMatrix();
		Point dx = node.pos.sub(lightPos).normalize().mul(radius * 10);
		Color.black.set();
		GL11.glPushMatrix();
		Color.black.set();
		GL11.glTranslatef(node.pos.x, node.pos.y, 0);
		GL11.glBegin(GL11.GL_QUADS);
		for (int i = 0; i < verts.size() - 1; i++) {
			for (int j = i + 1; j < verts.size(); j++) {
				Point s = verts.get(i).rotate(node.apos);
				Point e = verts.get(j).rotate(node.apos);
				s.x *= node.scale.x;
				s.y *= node.scale.y;
				e.x *= node.scale.x;
				e.y *= node.scale.y;
				Point b = s.add(s.add(node.pos).sub(lightPos).normalize().mul(radius * 5));
				Point d = e.add(e.add(node.pos).sub(lightPos).normalize().mul(radius * 5));
				GL11.glVertex2f(s.x, s.y);
				GL11.glVertex2f(e.x, e.y);
				GL11.glVertex2f(d.x, d.y);
				GL11.glVertex2f(b.x, b.y);
				s = b.add(dx);
				e = d.add(dx);
				GL11.glVertex2f(s.x, s.y);
				GL11.glVertex2f(e.x, e.y);
				GL11.glVertex2f(d.x, d.y);
				GL11.glVertex2f(b.x, b.y);
			}
		}
		GL11.glEnd();
		GL11.glPopMatrix();
	}
	@Override
	public void drawGlow() {
		GL11.glPushMatrix();
		node.setUpGl();
		if (vbo != null && this.hasGlow())
			vbo.drawAt(Point.ZERO, 0, glowColor);
		GL11.glPopMatrix();
	}
	@Override
	public void delete() {
		if (vbo != null)
			vbo.delete();
	}
	public Point[] getVerts() {
		Point v[] = new Point[verts.size()];
		for (int i = 0; i < verts.size(); i++) {
			v[i] = verts.get(i);
		}
		return v;
	}
	@Override
	public String toFileString() {
		String s = super.toFileString();
		for (Point p : verts) {
			s = s + "/" + p.toFileString();
		}
		return s;
	}
	@Override
	public int fromFileString(String s) {
		int off = super.fromFileString(s);
		String l[] = s.split("/");
		for (int i = off + 1; i < l.length; i++) {
			this.verts.add(Point.valueOf(l[i]));
		}
		node.boundingrad = 0;
		for (int i = 0; i < verts.size(); i++) {
			node.boundingrad = Math.max(node.boundingrad, verts.get(i).length());
		}
		this.vbo = new VertexBufferObject(getVerts(), Drawmode.POLYGON);
		globalCoords = true;
		return off + 1 + verts.size();
	}
	@Override
	public void setGlobalCoords(boolean gc) {
		// Polygons can not have local texture coords (this would require additional texture coord data)
		this.globalCoords = true;
	}
	private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
		in.defaultReadObject();
		this.vbo = new VertexBufferObject(getVerts(), Drawmode.POLYGON);
	}
}
